home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Sample code demonstrating how to patch PowerOff key
- **
- ** by Brian Bechtel, Apple Developer Technical Support
- **
- ** File: PatchPowerOff.c
- **
- ** Copyright © 1995 Apple Computer, Inc.
- ** All rights reserved.
- **
- ** You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DTS Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes.
- */
- #include <Gestalt.h>
- #include <Resources.h>
- #include <Errors.h>
- #include <OSUtils.h>
- #include <Traps.h>
- #include <SetupA4.h>
- #include <A4Stuff.h>
-
- /* from the 7.5.3 tech note */
- #ifdef PowerPC
- enum {
- uppPowerOffProcInfo = kPascalStackBased
- | STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
- | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
- };
- #endif
-
- /* constants used as parameters to the power off key routine */
- enum {
- kPowerKey = 0x7F,
- kDissablePwKy = 0x6B,
- kEnablePwKy = 0x00,
-
- kShutdownDlog = 0x7E,
- kNoDismiss = 0x00,
- kOneSecond = 0x70,
- kTenSeconds = 0x400
- };
-
- /* declaration for the power off key routine */
- typedef pascal OSErr (*PwrKeyProc)(short item, short action);
-
- /* for debugging */
- #define assert(i) if ((i) DebugStr("\p;printf \"assertion failed file %s line %d\" __FILE__, __LINE__")
-
- #define kINITid 0 /* matches the resID in the 68K Project preferences */
- #define kICONid 128
-
- pascal void ShowIcon7(short iconId, Boolean advance);
-
- // local function declarations
- void InitAlertPatch(void);
- void ClearAlertPatch(void);
- void asm AlertPatch(void);
- OSErr DisablePowerOffKey(void);
- void main(void);
-
- static long gOriginalTrapPtr = 0;
- static Boolean gAlertPatchIsInstalled = false;
-
- /*
- * InstallAlertPatch
- * This routine patches the Alert() trap so that we can check for
- * the PowerOff alert and dismiss it before it comes up.
- */
- void InitAlertPatch(void)
- {
- if (gAlertPatchIsInstalled == false)
- {
- gOriginalTrapPtr = (long) NGetTrapAddress( _Alert, ToolTrap);
- NSetTrapAddress( (UniversalProcPtr)(AlertPatch), _Alert, ToolTrap);
- gAlertPatchIsInstalled = true;
- }
- }
-
- /*
- * ClearAlertPatch
- * This routine clears out the patch we installed in InstallAlertPatch.
- * Note: Never call this routine from within an extension; you don't know
- * what other patches may have been put on Alert() after you installed
- * your patch, and bad things would happen if you eliminate yourself from
- * the chain of patches...
- */
- void ClearAlertPatch(void)
- {
- if (gAlertPatchIsInstalled == true)
- {
- NSetTrapAddress( (UniversalProcPtr)(gOriginalTrapPtr), _Alert, ToolTrap);
- gAlertPatchIsInstalled = false;
- }
- }
-
- /*
- * AlertPatch
- * This patch checks to see if we are about to display alert -16500. This
- * is the ALRT id used by the dialog which asks if you want to shutdown, etc.
- * If we are about to show that dialog, fake things up as if we have already
- * shown the dialog, and the user has pressed the Cancel button. The result
- * is that the dialog is never shown, and no action is taken. Just as if
- * the PowerOff code was never added to the system...
- * Call this routine only if the programmatic method (using the 'pwky' Gestalt
- * selector) fails.
- * This patch trashes register a0 and possibly register d0, but
- * these registers are trashed by Alert anyway.
- */
- void asm AlertPatch(void)
- {
- // Check for proper alert. If it's the trap we want to avoid,
- // return to caller without actually executing the Alert trap.
- // Set up the stack so it looks as if the user hit okay.
-
- PatchPowerOff:
- // test for specific PowerOff dialog id. If we find it, return as if we hit cancel.
- move.w 8(sp), d0 // now d0 has the dialog ID
- cmpi.w #-16500,d0 // we want to avoid -16500
- bne exitPatchPowerOff
- // if it's the alert we want, return to caller without
- // executing the alert.
- // FUNCTION Alert ( alertID: INTEGER; filterProc: ProcPtr) : INTEGER;
- // means that the stack looks like this:
- // sp + 0 -> return address (4 bytes)
- // + 4 -> filterProc (4 bytes)
- // + 8 -> alertID (2 bytes)
- movea.l (sp)+, a0 // the caller's return address
- lea 6(sp), sp // clear off the parms put on by caller
- move.w #2, (sp) // tell the system we hit cancel. (2nd button = cancel)
- jmp (a0) // return to caller without actually calling Alert
-
- exitPatchPowerOff:
- // call the original trap.
- //First, set up a4 to access the old trap address
- jsr SetUpA4 // puts old a4 into register d0
-
- lea gOriginalTrapPtr, a0
-
- exg d0, a4 // restore old value of a4
-
- movea.l (a0), a0
- jmp (a0)
- }
-
- /*
- * DisablePowerOffKey
- * This routine will either call the routine pointed to by the Gestalt
- * selector 'pwky', telling it to disable the power off key, or this
- * routine will return an error (usually telling you the Gestalt selector
- * is not installed.)
- */
- OSErr DisablePowerOffKey(void)
- {
- OSErr err;
- PwrKeyProc pPwrKey;
- err = Gestalt('pwky', (long*) &pPwrKey);
- if ( (long) pPwrKey == nil )
- err = gestaltUndefSelectorErr; // no proc ptr means no selector
- if ( err == noErr )
- #ifdef PowerPC
- err = CallUniversalProc((UniversalProcPtr) pPwrKey,
- uppPowerOffProcInfo, kPowerKey, kDissablePwKy);
- #else
- err = pPwrKey(kPowerKey, kDissablePwKy);
- #endif
- return err;
- }
-
-
- /* main */
-
- void main(void)
- {
- long oldA4;
- Handle h;
- OSErr err = noErr;
-
- #ifdef USE_DEBUGGER_CALLS
- Debugger();
- #endif
-
- /* set up our A4 context for _this file_ */
- oldA4 = SetCurrentA4();
- RememberA4();
-
- /* First try to disable the power key programmatically.
- * If that doesn't work, do a skanky hack.
- */
- if (DisablePowerOffKey() != noErr)
- {
- /* detach ourselves */
- h = Get1Resource('INIT', kINITid);
- if (h) DetachResource(h);
-
- InitAlertPatch();
- }
- ShowIcon7(kICONid, true);
-
- /* restore the a4 world */
- SetA4(oldA4);
- }
-